返回设计模式博客目录
|
第一篇:单一职责原则
第二篇:开闭原则
第三篇:里氏替换原则
第四篇:依赖倒置原则
第五篇:接口隔离原则
第六篇:迪米特原则
接口隔离原则
英文全称是 Interface Segregation Principles,ISP。其定义是:客户端不应该依赖它不需要的接口。另一种定义是:类间的依赖关系应该建立在最小的接口上。接口隔离原则将非常庞大、臃肿的接口拆分成更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。接口隔离原则的目的是系统解开耦合,从而容易重构、更改和重新部署。
说白了就是,让客户端依赖的接口尽可能地小。这样说可能还有点抽象,我们还是以一个示例来说明一下。在此之前我们来说一个场景,在 Java 6 及之前的 JDK 版本,有一个非常讨厌的问题,那就是在使用了 OutputStream 或者其他可关闭的对象之后,我们必须保证他们最终被关闭了,我们的 SD 卡缓存类中就有这样的代码。
我们看到的这段代码可读性非常差,各种 try…catch 嵌套都是些简单的代码,但是会严重影响代码的可读性,并且多层次的大括号很容易将代码写到错误的层级中。
在 Java 中有一个 Closeable 接口,该接口标识了一个可关闭的对象,它只有一个 close 方法。如下图所示:
我们要讲的 FileOutputStream 类就实现了这个接口。我们从上图可以看到,还有 100 多个类实现了 Closeable 这个接口。这意味着,在关闭这 100 多个类型的对象时,都需要写出像 put 方法中 finally 代码段那样的代码。这还了得,反正我是不能忍。既然都是实现了 Closeable 接口,那只要一个方法统一来关闭这些对象不就可以了么?于是写来来如下的工具类。
我们再看看把这段代码运用到上述的 put 方法中的效果如何。
代码简洁了很多!而且这个 closeQuietly 方法可以运用到各类可关闭的对象中,保证了代码的重用性。CloseUtils 的 closeQuietly 方法的基本原理就是依赖于 Closeable 抽象而不是具体实现,并且建立在最小化依赖原则的基础上,它只需要知道这个对象是可关闭的,其他的一概不关心,也就是这里的接口隔离原则。
试想一下,如果在只是需要关闭一个对象时,它却暴露了其他的接口函数,如 OutputStream 的 write 方法,这就使得更多的细节暴露在客户端代码面前,不仅没有很好地隐藏实现,还增加了接口的使用难度。而通过 Closeable 接口将可关闭的对象抽象起来,这样只需要客户端依赖于 Closeable 就可以对客户端隐藏其他的接口信息,客户端代码只需要知道这个对象可关闭(只可调用 close 方法)即可。
之前博客中设计的 ImageLoader 持有的 ImageCache 就是接口隔离原则的运用。ImageLoader 只需要知道该缓存对象有存、取缓存图片的接口即可,其他的一概不管,这就使得缓存功能的具体实现对 ImageLoader 隐藏。这就是用最小化接口隔离了实现类的细节,也促使我们将庞大的接口拆分到更细粒度的接口当中,这使得我们的系统具有更低的耦合性、更高的灵活性。
举例:拆分接口
依据接口隔离原则,将下图中臃肿的接口 I 拆分为独立的几个接口。
类 A 依赖接口 I 中的方法1、方法2、方法3,类 PA 是对类 A 依赖的实现。类 B 依赖接口 I 中的方法1、方法4、方法5,类 PB 是对类 B 依赖的实现。对于类 PA 和类 PB 来说,虽然他们都存在着用不到的方法(也就是图中划红线的方法),但由于实现了接口 I,所以也必须要实现这些用不到的方法。用代码表示如下:
可以看到,如果接口过于臃肿,只要接口中出现的方法,不管对依赖于它的类有没有用处,实现类中都必须去实现这些方法,这显然不是好的设计。如果将这个设计修改为符合接口隔离原则,就必须对接口 I 进行拆分。在这里我们将原有的接口 I 拆分为三个接口,拆分后的设计如下图所示:
代码更改如下:
接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。本文例子中,将一个庞大的接口变更为 3 个专用的接口所采用的就是接口隔离原则。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
说到这里,很多人会觉的接口隔离原则跟之前的单一职责原则很相似,其实不然。其一,单一职责原则原注重的是职责;而接口隔离原则注重对接口依赖的隔离。其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口接口,主要针对抽象,针对程序整体框架的构建。
采用接口隔离原则对接口进行约束时,要注意以下几点:
- 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化,所以一定要适度。
- 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
- 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
运用接口隔离原则,一定要适度,接口设计的过大或过小都不好。设计接口的时候,只有多花些时间去思考和筹划,才能准确地实践这一原则。